﻿using System;

using BodaNetCommunications.CommBase.Addresses;

namespace BodaNetCommunications.ModbusTcpComs
{
    public class ModbusAddress : DeviceAddressBase
    {
        #region Constructor

        /// <summary>
        /// 实例化一个默认的对象
        /// </summary>
        public ModbusAddress()
        {
            Station = -1;
            Function = ModbusFunctionCode.UnknowFunction;
            Address = 0;
        }

        /// <summary>
        /// 实例化一个默认的对象，使用默认的地址初始化
        /// </summary>
        /// <param name="address">传入的地址信息，支持富地址，例如s=2;x=3;100</param>
        public ModbusAddress(string address, bool isRead)
        {
            Station = -1;
            Function = ModbusFunctionCode.UnknowFunction;
            IsRead = isRead;
            Address = 0;
            Parse(address);
        }

        /// <summary>
        /// 实例化一个默认的对象，使用默认的地址初始化
        /// </summary>
        /// <param name="address">传入的地址信息，支持富地址，例如s=2;x=3;100</param>
        /// <param name="function">默认的功能码信息</param>
        /// <param name="isRead">是否为读取数据</param>
        public ModbusAddress(string address, ModbusFunctionCode function)
        {
            Station = -1;
            Address = 0;
            Function = function;
            Parse(address);
        }

        /// <summary>
        /// 实例化一个默认的对象，使用默认的地址初始化
        /// </summary>
        /// <param name="station">站号信息</param>
        /// <param name="function">功能码信息</param>
        /// <param name="address">地址信息</param>
        public ModbusAddress(byte station, ModbusFunctionCode function, ushort address)
        {
            Station = -1;
            Function = function;
            Address = 0;
        }

        #endregion Constructor

        #region Public Properties

        /// <summary>
        /// 站号信息
        /// </summary>
        public int Station { get; set; }

        /// <summary>
        /// 功能码
        /// </summary>
        public ModbusFunctionCode Function { get; set; }

        /// <summary>
        /// 是否读取功能
        /// </summary>
        public bool IsRead { get; set; } = true;

        #endregion Public Properties

        #region Analysis Address

        /// <summary>
        /// 解析Modbus的地址码，如果没有指定功能码，则会分析功能码：
        /// 1. 支持富地址，例如s=2;x=3;100
        /// 2. 如果地址时40010, 则会被修改为10
        /// 3. 如果需要写多个寄存器或者线圈，需要指定具体的功能码
        /// </summary>
        /// <param name="address">地址数据信息</param>
        public override void Parse(string address)
        {
            if (address.IndexOf(';') < 0)
            {
                // 正常地址，功能码03
                Address = ushort.Parse(address);

                // 获取原始的地址
                if (Address >= 40000)
                {
                    Address = (ushort)(Address % 40000);
                    // 如果没有指定功能码，则按照地址去指定功能码
                    if (Function == ModbusFunctionCode.UnknowFunction) Function = IsRead ? ModbusFunctionCode.ReadRegister : ModbusFunctionCode.WriteOneRegister;
                }
                else if (Address >= 30000)
                {
                    Address = (ushort)(Address % 30000);
                    if (Function == ModbusFunctionCode.UnknowFunction) Function = IsRead ? ModbusFunctionCode.ReadInputRegister : ModbusFunctionCode.WriteOneRegister;
                }
                else if (Address >= 10000)
                {
                    Address = (ushort)(Address % 10000);
                    if (Function == ModbusFunctionCode.UnknowFunction) Function = IsRead ? ModbusFunctionCode.ReadDiscrete : ModbusFunctionCode.WriteOneCoil;
                }
                else
                {
                    if (Function == ModbusFunctionCode.UnknowFunction) Function = IsRead ? ModbusFunctionCode.ReadCoil : ModbusFunctionCode.WriteOneCoil;
                }
            }
            else //富文本地址
            {
                // 带功能码的地址
                string[] list = address.Split(';');
                for (int i = 0; i < list.Length; i++)
                {
                    if (list[i][0] == 's' || list[i][0] == 'S')
                    {
                        // 站号信息
                        this.Station = byte.Parse(list[i].Substring(2));
                    }
                    else if (list[i][0] == 'x' || list[i][0] == 'X')
                    {
                        this.Function = (ModbusFunctionCode)byte.Parse(list[i].Substring(2));
                    }
                    else
                    {
                        this.Address = ushort.Parse(list[i]);
                    }
                }
            }
        }

        /// <summary>
        /// 验证地址
        /// </summary>
        /// <param name="address">地址值</param>
        /// <param name="isBit">是否为线圈存储区</param>
        /// <param name="start">返回开始地址</param>
        /// <param name="offset">返回偏移地址</param>
        /// <returns></returns>
        public static bool VerifyModbusAddress(string address, bool isBit, out int start, out int offset)
        {
            address = address.Trim().Replace(" ", "");
            if (isBit)
            {
                offset = 0;
                return int.TryParse(address, out start);
            }
            else
            {
                if (address.Contains('.'))
                {
                    string[] result = address.Split('.');

                    if (result.Length == 2)
                    {
                        bool value = true;
                        int res = 0;
                        value &= int.TryParse(result[0], out res);
                        start = res;

                        value &= int.TryParse(result[1], out res);
                        offset = res;

                        return value;
                    }
                    else
                    {
                        start = offset = 0;
                        return false;
                    }
                }
                else
                {
                    offset = 0;
                    return int.TryParse(address, out start);
                }
            }
        }

        #endregion Analysis Address

        #region Address Operate

        /// <summary>
        /// 地址新增指定的数
        /// </summary>
        /// <param name="value">数据值信息</param>
        /// <returns>新增后的地址信息</returns>
        public ModbusAddress AddressAdd(int value)
        {
            return new ModbusAddress()
            {
                Station = this.Station,
                Function = this.Function,
                Address = (ushort)(this.Address + value),
            };
        }

        /// <summary>
        /// 地址新增1
        /// </summary>
        /// <returns>新增后的地址信息</returns>
        public ModbusAddress AddressAdd()
        {
            return AddressAdd(1);
        }

        #endregion Address Operate

        /// <summary>
        /// 创建一个读取寄存器的字节对象
        /// </summary>
        /// <param name="station">读取的站号</param>
        /// <param name="length">读取数据的长度</param>
        /// <returns>原始的modbus指令</returns>
        public byte[] CreateReadRegister(byte station, ushort length)
        {
            byte[] buffer = new byte[6];
            buffer[0] = this.Station < 0 ? station : (byte)this.Station;
            buffer[1] = this.Function < ModbusFunctionCode.ReadCoil ? (byte)ModbusFunctionCode.ReadRegister : (byte)this.Function;
            buffer[2] = BitConverter.GetBytes(this.Address)[1];
            buffer[3] = BitConverter.GetBytes(this.Address)[0];
            buffer[4] = BitConverter.GetBytes(length)[1];
            buffer[5] = BitConverter.GetBytes(length)[0];
            return buffer;
        }
    }
}